/**
 * UniformDistribution : Definition de la loi Uniforme
 *
 * @author maria ladoue
 * @version 0.1, 30/08/02 
 */
package br.unb.statistic.distribution;

import java.util.HashMap;
import br.unb.statistic.InterPacketTimeGenerator;
import br.unb.statistic.RandomGenerator;
import br.unb.statistic.inference.Inference;
import br.unb.utils.Resource;

public class UniformDistribution extends GenericContinuousDistribution implements RandomGenerator, InterPacketTimeGenerator {

    /**
     * Equation de la densite: (probability density)<BR>
     *  f(x) = 1/(b-a) if (x>a and x<b)
     */
    private static int A = 0;
    private static int B = 1;

    public UniformDistribution() {
        paramsCount = 2;
        name = new String("Uniform");
        paramNames = new String[paramsCount];
        paramNames[A] = new String("a");
        paramNames[B] = new String("b");
        params = new double[paramsCount];
        params[A] = 0.0d;
        params[B] = 1.0d;
    }

    public UniformDistribution(double a, double b)
            throws IllegalArgumentException {
        this();

        if (b > a) {
            params[A] = a;
            params[B] = b;
        } else {
            throw new IllegalArgumentException(Resource.getString("UNIFORMDISTRIBUTION.CONSTRUCTOR_B_<_A"));
        }
    }

    public UniformDistribution(double[] params)
            throws IllegalArgumentException {
        this();
        if (hasValidParam(params)) {
            setParams(params);
        } else {
            throw new IllegalArgumentException(Resource.getString("UNIFORMDISTRIBUTION.CONSTRUCTOR_B_<_A"));
        }
    }

    public boolean hasValidParam(double[] desParams) {
        if (desParams[A] >= desParams[B]) {
            return false;
        } else {
            return true;
        }
    }

    public void setParams(double[] params)
            throws IllegalArgumentException {

        if (params.length >= paramsCount && params[B] > params[A]) {
            this.params[A] = params[A];
            this.params[B] = params[B];
        } else {
            throw new IllegalArgumentException(Resource.getString("UNIFORMDISTRIBUTION.SETPARAMS_B_<_A"));
        }
    }

    public void setParam(int idx, double p)
            throws IllegalArgumentException {

        if (idx < paramsCount
                && ((p < params[B] && idx == A) || (p > params[A] && idx == B))) {
            params[idx] = p;
        } else {
            throw new IllegalArgumentException(Resource.getString("UNIFORMDISTRIBUTION.SETPARAM_B_<_A"));
        }
    }

    /**
     * Returns the value of the probability distribution function at x
     */
    public double pdf(double x) {

        if (x < params[A] || x > params[B]) {

            return 0.0d;
        } else {

            return 1.0d / (params[B] - params[A]);
        }
    }

    /**
     * Returns the value of the cumulative distribution function at x
     */
    public double cdf(double x) {

        if (x < params[A]) {

            return 0.0d;
        } else if (x > params[B]) {

            return 1.0d;
        } else {

            return (x - params[A]) / (params[B] - params[A]);
        }
    }

    /**
     * Return the value of Inverse Function at x
     * @param x with x>=0 and x<=1
     */
    public double inverseCdf(double x)
            throws IllegalArgumentException {

        if (x >= 0 && x <= 1) {
            return (params[A] + (params[B] - params[A]) * x);
        } else {
            throw new IllegalArgumentException(Resource.getString("UNIFORMDISTRIBUTION.INVERSECDF_IT_IS_DEFINED_ON_[0,1]."));
        }
    }

    public double rand() {
        return this.inverseCdf(random.nextDouble());
    }

    public double nextInterPacketTime() {
        return rand();
    }

    public double mean() {

        return (params[B] + params[A]) / 2;
    }

    public double var() {

        return Math.pow((params[A] - params[B]), 2) / 12.0;
    }

    public String getEquation() {
        return new String(" f(x) = 1/(b-a) if (x>a and x<b)");
    }

    public void setParameters(HashMap parameters) {
        double mean;
        if (parameters.get("mean") != null) {
            mean = Double.parseDouble((String) parameters.get("mean"));
        } else {
            mean = 1.0d / Double.parseDouble((String) parameters.get("rate"));
        }
        double a = Double.parseDouble((String) parameters.get("a"));
        if (mean > a) {
            params[A] = a;
            params[B] = (2 * mean) - a;
        }
    }

    public void estimateParameters(Inference inf) {
        double a = inf.getMin();
        double b = inf.getMax();
        params[A] = a;
        params[B] = b;
    }
    /* //Old code with the testing unit and stuff YO!!!
    public static void main(String args[]){
    UniformDistribution dist = new UniformDistribution(3.5,4.3);
    UniformDistribution dist2 = new UniformDistribution();
    Log log = new Log("teste",false);
    for(int i=0; i<3000; i++){
    log.write(""+dist.rand());
    }
    log.close();
    try {
    DataReader dr = new DataReader(log.getFile());
    Inference inf = new Inference(dr,0);
    dist2.calculateMLE(inf);
    System.out.println(dist2.getParam(0)+" "+dist2.getParam(1));
    } catch (IOException e) {
    e.printStackTrace();
    }
    }*/
}
